package de.swm.gwt.client.mobile.network;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;

import de.swm.gwt.client.eventbus.IDispatcher;
import de.swm.gwt.client.mobile.network.rpcservice.NetworkServiceAsync;



/**
 * Ueberwacht die Netzwerkverbindung und sendet Events wenn die Netzwerkverbindung ausfaellt.
 * 
 * @author wiese.daniel <br>
 *         copyright (C) 2011, SWM Services GmbH
 * 
 */
public class NetworkMonitor implements INetworkMonitor {

	private static final int NETWORK_CHECK_INTERVALL_MS = 30 * 1000;
	private static final int TIMEOUT_INTERVALL_MS = NETWORK_CHECK_INTERVALL_MS / 2;

	@Inject
	private IDispatcher dispatcher;

	@Inject
	private IVersionControlMonitor versionControlMonitor;

	private final NetworkServiceAsync networkService;

	private boolean networkAvailable = true;

	private Timer timer;

	private boolean isStarted = false;



	/**
	 * Guice constructor.
	 * 
	 * @param networkService
	 *            netwerk service endpoint
	 */

	@Inject
	public NetworkMonitor(NetworkServiceAsync networkService) {
		this.networkService = networkService;
	}



	/**
	 * {@inheritDoc}
	 * 
	 * @see de.swm.mvgfahrplan.client.network.INetworkMonitor#startService()
	 */
	@Override
	public void startService() {
		if (!isStarted) {
			isStarted = true;
			sendNetworkRequest();
			timer = new Timer() {
				@Override
				public void run() {
					sendNetworkRequest();
				}
			};
			timer.scheduleRepeating(NETWORK_CHECK_INTERVALL_MS);
			// wir nehmen an, dass nach dem Start das Netzwerk NICHT verfuegbar ist
			networkAvailable = false;
			dispatcher.fireMobileEvent(NetworkEvents.NETWORK_UNAVAILABLE);
		}
	}



	/**
	 * Sendet einen mit einem Timer befirsteten Request zum Server.
	 */
	public void sendNetworkRequest() {
		AsyncCallback<String> networkCheckResult = new AsyncCallback<String>() {

			@Override
			public void onFailure(Throwable caught) {
				if (networkAvailable) {
					networkAvailable = false;
					GWT.log("Sending Network-Unavailable Event");
					dispatcher.fireMobileEvent(NetworkEvents.NETWORK_UNAVAILABLE);
				}

			}



			@Override
			public void onSuccess(String result) {
				if (result != null && !result.equalsIgnoreCase("OK")) {
					// send timestamp to version monitor
					versionControlMonitor.publishServerSideVersion(result);
				}
				if (!networkAvailable) {
					networkAvailable = true;
					GWT.log("Sending Network-Available Event");
					dispatcher.fireMobileEvent(NetworkEvents.NETWORK_AVAILABLE);
				}

			}
		};
		if (isStarted) {
			networkService.checkNetwork(new AsyncCallbackWithTimeout<String>(networkCheckResult, TIMEOUT_INTERVALL_MS));
		}
	}



	@Override
	public void stopService() {
		if (isStarted) {
			isStarted = false;
			if (timer != null) {
				timer.cancel();
			}
			//Annahme: Fwenn der service gestoppt wird ist das netz nicht verfugbar
			dispatcher.fireMobileEvent(NetworkEvents.NETWORK_UNAVAILABLE);
		}

	}

}
